home *** CD-ROM | disk | FTP | other *** search
/ Die Speccy' 97 / Die Speccy' 97.iso / amiga_system / the_aminet / util / shell / csh548src.lha / execom.c < prev    next >
C/C++ Source or Header  |  1995-09-13  |  51KB  |  2,023 lines

  1. /*
  2.  * EXECOM.C
  3.  *
  4.  * Matthew Dillon, 10 August 1986
  5.  * Version 2.07M by Steve Drew 10-Sep-87
  6.  * Version 4.01A by Carlo Borreo & Cesare Dieni 17-Feb-90
  7.  * Version 5.00L by Urban Mueller 17-Feb-91
  8.  * Version 5.20L by Andreas M. Kirchwitz (Fri, 13 Mar 1992)
  9.  *
  10.  */
  11.  
  12. #include "shell.h"
  13.  
  14. #define DEFAULTFRAME 1024
  15. #define Strlen(x)    strlen((char*)x)
  16. #define Strcpy(x,y)  strcpy((char*)x,(char*)y)
  17. #define Strcat(x,y)  strcat((char*)x,(char*)y)
  18. #define Index(x,y)   ((UBYTE*)index((char*)x,y))
  19. #define CHECKAV(num) { if( ac+num+10>max_ac ) checkav( frameptr, num ); }
  20.  
  21. typedef struct StackFrame {
  22.     struct StackFrame *next;
  23.     int  bytesleft;
  24.     char *ptr;
  25.     char mem[1];
  26. } FRAME;
  27.  
  28. /* execom.c */
  29. int   fcomm(UBYTE *str,FRAME **frame,char *from );
  30. int   hasspace( char *s );
  31. int   myfgets( char *buf, FILE *in );
  32.  
  33. static char  *compile_avf(FRAME **frame,char **av,int start,int end,char delim,int quote);
  34. static int   preformat(char *s, UBYTE *d);
  35. static void  backtrans(UBYTE *str);
  36. static UBYTE *exarg(UBYTE **ptr, UBYTE *elast);
  37. static UBYTE *format_insert_string(FRAME **frameptr, UBYTE *str, char *from);
  38. static int   find_command(char *str);
  39. static int   checkav( FRAME **frame,int n );
  40. static char  *tempname( int which );
  41. static UBYTE *skipword( UBYTE *strskip );
  42.  
  43. static void  newframe( FRAME **frame, int bytes);
  44. static void  *falloc( FRAME **frame, int bytes );
  45. static void  *frealloc( FRAME **frame, char *oldstring, int morebytes );
  46. static void  funalloc( FRAME **frame, int bytes );
  47. static char  *push_cpy( FRAME **frame, void *s);
  48. static void  deleteframe( FRAME *frame);
  49.  
  50. void  exec_every(void);
  51.  
  52. int do_nothing(void);
  53.  
  54. struct COMMAND {
  55.     int (*func)();
  56.     short minargs;
  57.     short stat;
  58.     int val;
  59.     char *name;
  60.     char *options;
  61.     char *usage;
  62. };
  63.  
  64. #define ST_COND   0x01 /* this is an 'if' type command, no redirection */
  65. #define ST_NORED  0x02 /* this command can't be redirected             */
  66. #define ST_NOEXP  0x04 /* no wild card expansion for this command      */
  67. #define ST_A0     0x08 /* delimit args with 0xA0 instead of ' '        */
  68. #define ST_FUNC   0x10 /* can be used as a function                    */
  69. #define ST_STORED 0x20 /* stores redirection instead of execuing it    */
  70. #define ST_AVLINE 0x40 /* needs avline                                 */
  71.  
  72. #define COND  ST_COND
  73. #define NORED ST_NORED
  74. #define STRED ST_STORED
  75. #define NOEXP ST_NOEXP
  76. #define A0   (ST_A0|ST_AVLINE)
  77. #define AV    ST_AVLINE
  78. #define FUNC  ST_FUNC
  79.  
  80. #define ALIAS LEVEL_ALIAS
  81. #define SET   LEVEL_SET
  82.  
  83. #define FIRSTCOMMAND 4
  84. #define COM_EXEC 3
  85.  
  86. static struct COMMAND Command[] = {
  87.  do_run,       0,   A0,     0, "\001",       NULL, NULL, /* may call do_source, do_cd */
  88.  do_nothing,   0,    0,     0, "\002",       NULL, NULL, /* dummy for aliases   */
  89.  do_nothing,   0,    0,     0, "\003",       NULL, NULL, /* dummy for aliases with args */
  90.  do_run,       0,NORED|A0,  1, "\004",       NULL, NULL, /* external that needs to be Execute()d */
  91.  do_abortline, 0,    0,     0, "abortline",  NULL, "",
  92.  do_action,    2,   AV,     9, "action",     "av", "action file [args]",
  93.  do_addbuffers,1,    0,     0, "addbuffers", NULL, "{drive [bufs]}",
  94.  do_tackon,    3, FUNC,     0, "addpart",    NULL, "var pathname filename",
  95.  do_set_var,   0,    0, ALIAS, "alias",      NULL, "[name [string] ]",
  96.  do_ascii,     0,    0,     0, "ascii",      "oh", "-oh [string]",
  97.  do_assign,    0,    0,     0, "assign",     "adpln",",logical,-adp {logical physical}",
  98.  do_basename,  2, FUNC,     0, "basename",   NULL, "var path",
  99.  do_cat,       0,    0,     0, "cat",        "n",  "-n [file file...]",
  100.  do_cd,        0,    0,     0, "cd",         "g",  "[path],-g path...path",
  101.  do_chgrp,     2,    0,     0, "chgrp",      NULL, "group file...file",
  102.  do_chmod,     2,    0,     0, "chmod",      NULL, "flags file...file",
  103.  do_chown,     2,    0,     0, "chown",      "g", "owner file...file",
  104.  do_class,     0,   A0,     0, "class",      "n",  "-n name {type=param} \"actions\" {action=command}",
  105.  do_close,     0,    0,     0, "close",      NULL, "filenumber",
  106.  do_copy,      1,    0,     0, "copy",       "rudpfmqoax","-adfmopqrux file file,-ud file...file dir,-ud dir...dir dir",
  107.  do_copy,      1,    0,     0, "cp",         "rudpfmqoax","-adfmopqrux file file,-ud file...file dir,-ud dir...dir dir",
  108.  do_date,      0,    0,     0, "date",       "srb","-bsr [date/time]",
  109.  do_inc,       1,    0,    -1, "dec",        NULL, "varname [step]",
  110.  do_rm,        0,    0,     0, "delete",     "rfpqv","-fpqrv file...file",
  111.  do_dir,       0,NOEXP,     0, "dir",        "sfdcnhltbuikqavopzegL","-abcdefghiklnopqstuvL [-z lformat] [path...path]",
  112.  do_diskchange,1,    0,     0, "diskchange", NULL, "drive...drive",
  113.  do_echo,      0,    0,     0, "echo",       "ne", "-ne string",
  114.  do_if,        0, COND,     1, "else",       NULL, "",
  115.  do_if,        0, COND,     2, "endif",      NULL, "",
  116.  do_error,     1,    0,     0, "error",      NULL, "num",
  117.  do_exec,      1,   AV,     0, "exec",       "i",  "-i command",
  118.  do_fault,     1,    0,     0, "fault",      NULL, "error",
  119.  do_filenote,  1,    0,     0, "filenote",   "s",  "file...file note,-s file...file",
  120.  do_fileslist, 0,    0,     0, "flist",      NULL, "",
  121.  do_fltlower,  0,    0,     0, "fltlower",   NULL, "<in >out",
  122.  do_fltupper,  0,    0,     0, "fltupper",   NULL, "<in >out",
  123.  do_foreach,   3,    0,     0, "foreach",    "v",  "-v varname ( string ) command",
  124.  do_forever,   1,   AV,     0, "forever",    NULL, "command",
  125.  do_forline,   3,    0,     0, "forline",    NULL, "var filename command",
  126.  do_fornum,    4,    0,     0, "fornum",     "vs", "-vs var n1 n2 command",
  127.  do_getenv,    1, FUNC,     0, "getenv",     NULL, "shellvar envvar",
  128.  do_goto,      1,    0,     0, "goto",       NULL, "label",
  129.  do_head,      0,    0,     0, "head",       NULL, "[filename] [num]",
  130.  do_help,      0,    0,     0, "help",       "f",  "help -f",
  131.  do_history,   0,    0,     0, "history",    "nr", "-nr [partial_string]",
  132.  do_howmany,   0,    0,     0, "howmany",    NULL, "",
  133.  do_htype,     0,    0,     0, "htype",      "r",  "-r [file...file]",
  134.  do_if,        1,COND|NORED,0, "if",         "rftmdvone","-n arg cond arg,-n arg,-nf file,-nd dir,-nm,-nt file...file,-nr rpn_expr,-no opt args,-v varname",
  135.  do_inc,       1,    0,     1, "inc",        NULL, "varname [step]",
  136.  do_info,      0,    0,     0, "info",       "pt", "-pt [drive...drive]",
  137.  do_input,     1,    0,     0, "input",      "sr", "-rs var...var",
  138.  do_join,      2,    0,     1, "join",       "r",  "-r file...file",
  139.  do_keymap,    1,    0,     0, "keymap",     "n",  "-n number {key=function}",
  140.  do_label,     1, COND,     0, "label",      NULL, "name",
  141.  do_local,     0,    0,     0, "local",      NULL, "[var...var]",
  142.  do_linecnt,   0,    0,     0, "linecnt",    NULL, "<in >out",
  143.  do_ln,        1,    0,     0, "ln",         "s",  "-s original [link]",
  144.  do_dir,       0,NOEXP,     0, "ls",         "sfdcnhltbuikqavopzegL","-abcdefghiklnopqstuvL [-z format] [path...path]",
  145.  do_ln,        1,    0,     0, "makelink",   "s", "-s original [link]",
  146.  do_man,       0,    0,     0, "man",        NULL, "command...command",
  147.  do_mkdir,     1,    0,     0, "md",         "p",  "-p name...name",
  148.  do_mem,       0,    0,     0, "mem",        "cfqsrl","-cflqsr",
  149.  do_menu,      0,    0,     0, "menu",       "nm", "-nm [title item...item]",
  150.  do_mkdir,     1,    0,     0, "mkdir",      "p",  "-p name...name",
  151.  do_mv,        2,    0,     0, "mv",         "fv", "-fv from to,from...from todir",
  152.  do_open,      3,    0,     0, "open",       NULL, "file mode number",
  153.  do_path,      0,    0,     0, "path",       "rg", "-gr [dir...dir]",
  154.  do_pri,       2,    0,     0, "pri",        NULL, "clinumber pri,0 pri",
  155.  do_protect,   2,    0,     0, "protect",    NULL, "file...file flags",
  156.  do_ps,        0,    0,     0, "ps",         "les","-els [commandname...commandname]",
  157.  do_pwd,       0,    0,     0, "pwd",        NULL, "",
  158.  do_qsort,     0,    0,     0, "qsort",      "rc",  "-cr <in >out",
  159.  do_quit,      0,NORED,     0, "quit",       NULL, "",
  160.  do_truerun,   1,NORED|AV,  1, "rback",      NULL, "command",
  161.  do_mv,        2,    0,     0, "rename",     "fv", "-fv from to,from...from todir",
  162.  do_readfile,  1,    0,     0, "readfile",   NULL, "varname [filename]",
  163.  do_rehash,    0,    0,     0, "rehash",     "closg","-cglos",
  164.  do_relabel,   2,    0,     0, "relabel",    NULL, "drive name",
  165.  do_resident,  0,    0,     0, "resident",   "ard",",-ard file...file",
  166.  do_return,    0,    0,     0, "return",     NULL, "[n]",
  167.  do_rm,        0,    0,     0, "rm",         "rfpqv","-fpqrv file...file",
  168.  do_rpn,       0,NOEXP,     0, "rpn",        NULL, "expression",
  169.  do_rxrec,     0,    0,     0, "rxrec",      NULL, "[portname]",
  170.  do_rxsend,    2,   AV,     0, "rxsend",     "rl", "-lc portname string",
  171.  do_truerun,   1,STRED|AV,  0, "run",        NULL, "command",
  172.  do_search,    2,    0,     0, "search",     "rcwneqvbfalo","-abceflnoqrvw file...file string",
  173.  do_set_var,   0,    0,   SET, "set",        NULL, "[name [string] ]",
  174.  do_setenv,    2,    0,     0, "setenv",     NULL, "var value",
  175.  do_sleep,     0,    0,     0, "sleep",      "t", "timeout",
  176.  do_split,     1,    0,     0, "split",      NULL, "srcvar dstvar...dstvar",
  177.  do_source,    1,   A0,     0, "source",     NULL, "file",
  178.  do_stack,     0,    0,     0, "stack",      "s",  "-s [bytes]",
  179.  do_strhead,   3, FUNC,     0, "strhead",    NULL, "varname breakchar string",
  180.  do_strings,   0,    0,     0, "strings",    "rbnv", "-bnrv [file...file] [minlength]",
  181.  do_strleft,   3, FUNC,     0, "strleft",    NULL, "varname string n",
  182.  do_strlen,    2, FUNC,     0, "strlen",     NULL, "varname string",
  183.  do_strmid,    3, FUNC,     0, "strmid",     NULL, "varname string n1 [n2]",
  184.  do_strright,  3, FUNC,     0, "strright",   NULL, "varname string n",
  185.  do_strtail,   3, FUNC,     0, "strtail",    NULL, "varname breakchar string",
  186.  do_tackon,    3, FUNC,     0, "tackon",     NULL, "var pathname filename",
  187.  do_head,      0,    0,     1, "tail",       NULL, "[filename] [num]",
  188.  do_tee,       0,    0,     0, "tee",        NULL, "<in >out",
  189.  do_touch,     1,    0,     0, "touch",      NULL, "file...file",
  190.  do_truncate,  0,    0,     0, "truncate",   NULL, "<in >out",
  191.  do_cat,       0,    0,     0, "type",       "n",  "-n [file...file]",
  192.  do_unset_var, 0,   AV, ALIAS, "unalias",    NULL, "name...name",
  193.  do_uniq,      0,    0,     0, "uniq",       NULL, "<in >out",
  194.  do_unset_var, 0,    0,   SET, "unset",      NULL, "name...name",
  195.  do_usage,     0,    0,     0, "usage",      NULL, "[command...command]",
  196.  do_version,   0,    0,     0, "version",    "filr", "[-filr name]",
  197.  do_waitport,  1,    0,     0, "waitforport",NULL, "portname [seconds]",
  198.  do_whereis,   1,NOEXP,     0, "whereis",    "r",  "-r file [path...path]",
  199.  do_window,    0,NOEXP,     0, "window",     "slfbaqwk","-slfbaqwk",
  200.  do_writefile, 1,    0,     0, "writefile",  NULL, "var >out",
  201.  NULL,         0,    0,     0, NULL,         NULL, NULL,
  202. };
  203.  
  204.  
  205. /* do_which,     1,    0,     0, "which",      NULL, "command", */
  206.  
  207. #ifdef isalphanum
  208. char isalph[256];
  209. #endif
  210.  
  211. int
  212. execute( char *str )
  213. {
  214.     ULONG toptions=options;
  215.     int   ret, oldac=ac, oldmax=max_ac;
  216.     char  **oldav=av;
  217.  
  218.     if( !str ) return -1;
  219.  
  220.     ++H_stack;
  221.     ret=exec_command(str);
  222.     --H_stack;
  223.  
  224.     av=oldav; max_ac=oldmax; ac=oldac;
  225.     options=toptions;
  226.  
  227.     return ret;
  228. }
  229.  
  230.  
  231. #if 1
  232. int
  233. exec_command( char *base )
  234. {
  235.     FRAME *frame=NULL;
  236.     UBYTE *scr;
  237.     char  buf[6];
  238.     int   len, newlen, ret;
  239.  
  240.     if (!H_stack && S_histlen>1) {
  241.         add_history(base);
  242.         sprintf(buf, "%d", H_tail_base + H_len);
  243.         set_var(LEVEL_SET, v_histnum, buf);
  244.     }
  245.  
  246.     len=Strlen(base)*3+20;
  247.     newframe( &frame, len+DEFAULTFRAME );
  248.  
  249.     scr   = falloc(&frame,len);
  250.     newlen= preformat( base,scr );
  251.  
  252.     funalloc( &frame, len-newlen-2 );
  253.     ret=fcomm(scr,&frame,NULL);
  254.  
  255.     deleteframe( frame );
  256.  
  257.     return ret;
  258. }
  259. #else
  260. int
  261. exec_command( char *base )
  262. {
  263.     FRAME *frame=NULL;
  264.     UBYTE *scr;
  265.     char  buf[6], expandbuf[1024];
  266.     int   len, newlen, ret;
  267.  
  268.    preprocess(base, expandbuf);  /* the call to my routine to process
  269.                     history shortcuts */
  270.  
  271.     if (!H_stack && S_histlen>1) {
  272.         add_history(expandbuf);
  273.         sprintf(buf, "%d", H_tail_base + H_len);
  274.         set_var(LEVEL_SET, v_histnum, buf);
  275.     }
  276.  
  277.     len=Strlen(expandbuf)*3+20;
  278.     newframe( &frame, len+DEFAULTFRAME );
  279.  
  280.     scr   = falloc(&frame,len);
  281.     newlen= preformat( expandbuf,scr );
  282.  
  283.     funalloc( &frame, len-newlen-2 );
  284.     ret=fcomm(scr,&frame,NULL);
  285.  
  286.     deleteframe( frame );
  287.  
  288.     return ret;
  289. }
  290.  
  291.  
  292. /* inserthistory() is called by preprocess() when every a '!' is 
  293. encountered.  So 'echo !!' will display the last line, for instance.
  294.     !!  The last line in history
  295.     !$  The last argument in the last line in history
  296.         'echo a b c' => 'c'
  297.     !*  Everything but the command in the last line in history
  298.         'echo a b c' => 'a b c'
  299. */
  300. static char  *inserthistory(char  *to, char  type)
  301. {
  302.    char  *lastline, *p;
  303.    
  304.    switch (type) {
  305.       case '!':
  306.          lastline = get_num_history(1);
  307.          to = stpcpy(to, lastline);
  308.          break;
  309.       case '$':
  310.          lastline = get_num_history(1);
  311.          p = lastline + strlen(lastline) - 1;
  312.         /* does not handle quoted arguments properly */
  313.          while (p >= lastline && !isspace(*p))
  314.             --p;
  315.          to = stpcpy(to, ++p);
  316.          break;
  317.       case '*':
  318.          lastline = get_num_history(1);
  319.          while (!isspace(*lastline) && *lastline)
  320.             ++lastline;
  321.          while (isspace(*lastline) && *lastline)
  322.             ++lastline;
  323.          to = stpcpy(to, lastline);
  324.          break;
  325.       default:
  326.          *to++ = type;
  327.          break;
  328.    }
  329.    return to;
  330. }
  331.  
  332. static void  preprocess(char  *from, char  *buf)
  333. {
  334.    int  printit = 0;
  335.    char  *to = buf;
  336.    int  quoteflag = 0;
  337.    
  338.    while (*from) {
  339.       switch (*from) {
  340.          case '!':
  341.             ++from;
  342.             to = inserthistory(to, *from);
  343.             printit = 1;
  344.             ++from;
  345.             break;
  346.          case '\\':
  347.             *to++ = *from++;
  348.             if (*from)
  349.                *to++ = *from++;
  350.             break;
  351.          case '\'':
  352.          case '"':
  353.             if (quoteflag == 0)
  354.                quoteflag = *from;
  355.             else if (quoteflag == *from) {
  356.                quoteflag = 0;
  357.             }
  358.             *to++ = *from++;
  359.             break;
  360.          default:
  361.             *to++ = *from++;
  362.             break;
  363.       }
  364.    }
  365.    *to = '\0';
  366.    if (printit)
  367.       fprintf(stderr, "'%s' => '%s'\n", from, buf);
  368. }
  369. #endif
  370.  
  371. #ifndef isalphanum
  372. isalphanum( char c )
  373. {
  374.     return (
  375.         (c >= 'a' && c <= 'z') ||
  376.         (c >= 'A' && c <= 'Z') ||
  377.         (c >= '0' && c <= '9') ||
  378.         (c == '_')
  379.     );
  380. }
  381. #endif
  382.  
  383. int isnum(char *s)
  384. {
  385.     int num = 0;
  386.     if (s) {
  387.         while(isspace(*s))   /* skip spaces */
  388.             s++;
  389.         if (*s=='-' || *s=='+')   /* skip sign */
  390.             s++;
  391.         num = isdigit(*s);   /* must be a digit */
  392.         while(isdigit(*s))   /* skip digits */
  393.             s++;
  394.         if (!(*s=='\0' || isspace(*s)))
  395.             num = 0;
  396.     }
  397.     return(num);
  398. }
  399.  
  400. #define HOT_GAP    0x80
  401. #define HOT_BLANK  0x81
  402. #define HOT_STAR   0x82
  403. #define HOT_QUES   0x83
  404. #define HOT_EXCL   0x84
  405. #define HOT_SEMI   0x85
  406. #define HOT_PIPE   0x86
  407. #define HOT_DOLLAR 0x87
  408. #define HOT_IN     0x88
  409. #define HOT_OUT    0x89
  410. #define HOT_BSLASH 0x8a
  411. #define HOT_LASTCD 0x8b
  412. #define HOT_BACKG  0x8c
  413. #define HOT_CURLL  0x8d
  414. #define HOT_CURLR  0x8e
  415. #define HOT_CURDIR 0x8f
  416. #define HOT_PARDIR 0x90
  417. #define HOT_BEGOUT 0x91
  418. #define HOT_ENDOUT 0x92
  419. #define HOT_EQUAL  0x93
  420. #define HOT_BEGIN  0x94
  421. #define HOT_APOSTR 0x95
  422. #if 1
  423. /* AMK: detect DOS patterns */
  424. #define HOT_PM1    0x96
  425. #define HOT_ECKL   0x97
  426. #define HOT_ECKR   0x98
  427. #endif
  428.  
  429. /* USHORT ArgPos[256]; */
  430.  
  431. static UBYTE termchar[]={ 0,    '}',       ')',        '`' };
  432. static UBYTE hotchar []={ 0, HOT_CURLR, HOT_ENDOUT, HOT_APOSTR };
  433.  
  434. static int
  435. preformat( char *src, UBYTE *d )
  436. {
  437.     int qm=0, i, level, curmode, argc=0, beg=1;
  438.     UBYTE mode[100], c, *s=(UBYTE*)src, *start=d;
  439.  
  440.     while (*s) {
  441.         if (qm ) {
  442.             /*
  443.                AMK:
  444.                Use 'o_cquote' here?
  445.                qm=quote mode?
  446.             */
  447.             while( isalphanum( *s ) || (*s && *s!='\"' && *s!='\\' && *s!='\n'))
  448.                 *d++ = *s++;
  449.             if( !*s ) break;
  450.             if( *s=='\n' ) qm=0, *s=';';
  451.         }
  452.         if( beg ) c=HOT_BEGIN,beg=0; else c = *s;
  453.         switch (c) {
  454.         case ' ':
  455.         case 9:
  456.             *d++ = HOT_BLANK;
  457. argstart:
  458.             while (*s==' ' || *s==9) ++s;
  459.             if( argc && (!*s || *s=='|' || *s==';' || *s=='#' || *s=='\n' ))--d;
  460.             if(      *s=='\\' && !argc ) { *d++=HOT_BSLASH; if( *d++ = *++s ) ++s; }
  461.             else if( *s=='~'  )          { *d++=HOT_LASTCD; s++; }
  462.             else if( *s=='.'  )
  463.                 for( ;; ) {
  464.                     if( s[0]=='.' && issep(s[1]))
  465.                         s+=1+(s[1]=='/');
  466.                     else if( s[0]=='.' && s[1]=='.' && issep(s[2]))
  467.                         *d++='/', s+=2+(s[2]=='/');
  468.                     else
  469.                         break;
  470.                 }
  471.             argc++;
  472.             break;
  473.         case '*':
  474.             *d++ = HOT_GAP;
  475.             *d++ = HOT_STAR;
  476.             ++s;
  477.             break;
  478.         case '?':
  479.             *d++ = HOT_GAP;
  480.             *d++ = HOT_QUES;
  481.             ++s;
  482.             break;
  483. #if 1
  484.         /* AMK --> detect DOS patterns */
  485. /*
  486.         case '(':
  487.             *d++ = HOT_GAP;
  488.             *d++ = HOT_PM1;
  489.             ++s;
  490.             break;
  491. */
  492.         case '[':
  493.             *d++ = HOT_GAP;
  494.             *d++ = HOT_ECKL;
  495.             ++s;
  496.             break;
  497.         case ']':
  498.             *d++ = HOT_GAP;
  499.             *d++ = HOT_ECKR;
  500.             ++s;
  501.             break;
  502.         /* <-- AMK */
  503. #endif
  504.         case '!':
  505.             *d++ = HOT_EXCL;
  506.             ++s;
  507.             break;
  508.         case HOT_BEGIN:
  509.             argc=0;
  510.             goto argstart;
  511.         case '#':
  512.             while (*s && *s!='\n') ++s;
  513.             if( !*s ) break;
  514.         case '\n':
  515.         case ';':
  516.             *d++= HOT_SEMI, argc=0, s++;
  517.             goto argstart;
  518.         case '|':
  519.             *d++= HOT_PIPE, argc=0, s++;
  520.             goto argstart;
  521.         case '\\':
  522.             if( (i = *++s-'0')>=0 && i<=7 ) {
  523.                 if( *++s>='0' && *s<='7' ) {
  524.                     i= 8*i + *s++-'0';
  525.                     if( *s>='0' && *s<='7' )
  526.                         i= 8*i + *s++-'0';
  527.                 }
  528.                 *d++ = i;
  529.             } else {
  530.                 *d++ = *s;
  531.                 if (*s) ++s;
  532.             }
  533.             break;
  534.         case '\"':
  535.             /*
  536.                AMK:
  537.                Use 'o_cquote' here?
  538.             */
  539.             if (o_cquote) {
  540.                 if (qm) {
  541.                     /*printf("\" ende (%s)\n",s);*/
  542.                     qm = 1 - qm;
  543.                     *d++ = HOT_BLANK;
  544.                     ++s;
  545.                     goto argstart;
  546.                 }
  547.                 else {
  548.                     if (s==src || (*(s-1)==' ') ) {
  549.                         /*printf("\" am beginn (%s)\n",s);*/
  550.                         qm = 1 - qm;
  551.                         ++s;
  552.                     }
  553.                     else {
  554.                         /*printf("\" mittendrin (%s)\n",s);*/
  555.                         *d++ = *s++;
  556.                     }
  557.                 }
  558.             }
  559.             else {    /* UNIX like quoting */
  560.                 qm = 1 - qm;
  561.                 ++s;
  562.             }
  563.             break;
  564.         case '^':
  565.             *d++ = *++s & 0x1F;
  566.             if (*s) ++s;
  567.             break;
  568.         case '<':
  569.             *d++ = HOT_IN;
  570.             ++s;
  571.             break;
  572.         case '>':
  573.             *d++ = HOT_OUT;
  574.             ++s;
  575.             break;
  576.         case '&':
  577.             *d++ = HOT_BACKG;
  578.             ++s;
  579.             break;
  580.         case '$': /* search end of var name */
  581.             if( s[1]=='(' ) {
  582.                 curmode=2;
  583.                 *d++=HOT_BEGOUT;
  584.                 *d++ = *++s;
  585.                 goto brace;
  586.             }
  587.             *d++ = HOT_GAP;
  588.             *d++ = HOT_DOLLAR;
  589.             ++s;
  590.             while (isalphanum(*s)) *d++ = *s++;
  591.             *d++ = HOT_GAP;
  592.             break;
  593.         case '`':
  594.             curmode=3;
  595.             *d++=HOT_APOSTR;
  596.             goto brace;
  597.         case '{':
  598.             curmode=1;
  599.             *d++ = HOT_CURLL;
  600. brace:
  601.             level=0; s++;
  602.             mode[level++]=curmode;
  603.             while( *s && level ) {
  604.                 switch( *s ) {
  605.                 /*
  606.                    AMK:
  607.                    Use 'o_cquote' here?
  608.                 */
  609.                 case '\"': *d++ = *s++;
  610.                            while( *s && *s!='\"' && *s!='\n')
  611.                                if( *s=='\\' ) { *d++ = *s++; if( *s ) *d++ = *s++; }
  612.                                else *d++ = *s++;
  613.                            if( *s ) *d++ = *s++;
  614.                            break;
  615.                 case '\\': *d++ = *s++; if( *s ) *d++ = *s++;
  616.                            break;
  617.                 case '{' : mode[level++]=1; *d++ = *s++;
  618.                            break;
  619.                 case '}' :
  620.                 case ')' :
  621.                 case '`' : for( i=level-1; i>=0 && termchar[mode[i]] != *s;--i ) ;
  622.                            if( i==0 ) *d++=hotchar [mode[i]];
  623.                            else       *d++ = *s;
  624.                            if( i>=0 ) level=i;
  625.                            s++;
  626.                            break;
  627.                 default  : *d++ = *s++;
  628.                            break;
  629.                 }
  630.             }
  631.             break;
  632.         default:
  633.             *d++ = *s++;
  634.             while( *s>=65 && (*s&31)<=26 )
  635.                 *d++ = *s++;
  636.             break;
  637.         }
  638.     }
  639. endwhile:
  640.     *d++=0;
  641.     *d=0;
  642.     if (debug) fprintf (stderr,"PREFORMAT: %d :%s:\n", Strlen(start), start);
  643.     return d-start;
  644. }
  645.  
  646. static void
  647. backtrans( UBYTE *str )
  648. {
  649.     if( !str )
  650.         return;
  651.  
  652.     while( *str ) {
  653.         while( *(signed char *)str>0 ) str++;
  654.         if( !*str ) break;
  655.         switch( *str) {
  656.             case HOT_GAP   : *str++=0;    break;
  657.             case HOT_BLANK : *str++=' ';  break;
  658.             case HOT_STAR  : *str++='*';  break;
  659.             case HOT_QUES  : *str++='?';  break;
  660.             case HOT_EXCL  : *str++='!';  break;
  661.             case HOT_SEMI  : *str++=';';  break;
  662.             case HOT_PIPE  : *str++='|';  break;
  663.             case HOT_DOLLAR: *str++='$';  break;
  664.             case HOT_IN    : *str++='<';  break;
  665.             case HOT_OUT   : *str++='>';  break;
  666.             case HOT_BSLASH: *str++='\\'; break;
  667.             case HOT_LASTCD: *str++='~';  break;
  668.             case HOT_BACKG : *str++='&';  break;
  669.             case HOT_CURLL : *str++='{';  break;
  670.             case HOT_CURLR : *str++='}';  break;
  671.             case HOT_CURDIR: *str++='.';  break;
  672.             case HOT_PARDIR: *str++='.';  break;
  673.             case HOT_BEGOUT: *str++='$';  break;
  674.             case HOT_ENDOUT: *str++=')';  break;
  675.             case HOT_EQUAL : *str++='=';  break;
  676.             case HOT_APOSTR: *str++='`';  break;
  677. #if 1
  678.             /* AMK --> detect DOS patterns */
  679. /*            case HOT_PM1   : *str++='(';  break;*/
  680.             case HOT_ECKL  : *str++='[';  break;
  681.             case HOT_ECKR  : *str++=']';  break;
  682.             /* <-- AMK */
  683. #endif
  684.             default        : str++;       break;
  685.         }
  686.     }
  687. }
  688.  
  689. /*
  690.  * process formatted string.  ' ' is the delimeter.
  691.  *
  692.  *    0: check '\0': no more, stop, done.
  693.  *    1: check $.     if so, extract, format, insert
  694.  *    2: check alias. if so, extract, format, insert. goto 1
  695.  *    3: check history or substitution, extract, format, insert. goto 1
  696.  *
  697.  *    4: assume first element now internal or disk based command.
  698.  *
  699.  *    5: extract each ' ' or 0x80 delimited argument and process, placing
  700.  *       in av[] list (except 0x80 args appended).  check in order:
  701.  *
  702.  *             '$'         insert string straight
  703.  *             '>'         setup stdout
  704.  *             '>>'        setup stdout flag for append
  705.  *             '<'         setup stdin
  706.  *             '*' or '?'  do directory search and insert as separate args.
  707.  *
  708.  *             ';' 0 '|'   end of command.  if '|' setup stdout
  709.  *                          -execute command, fix stdin and out (|) sets
  710.  *                           up stdin for next guy.
  711.  */
  712.  
  713. int  alias_count;
  714. int  has_wild;                 /* set if any arg has wild card */
  715. char *LastCommand;
  716. BPTR redir_out, redir_in;
  717.  
  718. #define MAXACDEF 32
  719.  
  720. int
  721. fcomm( UBYTE *str, FRAME **frameptr, char *from )
  722. {
  723.     UBYTE *nextstr, elast;
  724.     char *pend_alias, *command;
  725.     char cout_ispipe=0, cin_ispipe=0, cout_append=0;
  726.     char backg, firstrun, override, block, nobuiltin;
  727.     char *cin_name=NULL, *cout_name=NULL;
  728.     char **oldav=av;
  729.     signed char pendredir;
  730.     int  oldac=ac, oldmax=max_ac, err, ccno, cstat;
  731.     BOOL noclose_redir = FALSE;
  732.  
  733.     /* AMK: test for pattern matching detection */
  734.     int patterns_num=0,patterns_fail=0;
  735.  
  736.     max_ac= MAXACDEF;
  737.     av=(char **)falloc( frameptr, max_ac*sizeof(char *));
  738.     ac=0;
  739.  
  740.     if (++alias_count >= MAXALIAS) {           /* Recursion getting too deep? */
  741.         fprintf(stderr,"Alias Loop\n");
  742.         err = 20;
  743.         goto done1;
  744.     }
  745.  
  746. nextcommand:
  747.     command   = NULL;
  748.     pend_alias= NULL;
  749.     err       = 0;
  750.     has_wild  = 0;
  751.     firstrun  = 1;
  752.     ccno=cstat= 0;
  753.     elast     = 1;
  754.     block     = 0;
  755.     nobuiltin = 0;
  756.     pendredir = 0;
  757.     redir_in  = redir_out = 0;
  758.  
  759.     if (*str == 0)
  760.         goto done1;
  761.  
  762.     if ( *str == HOT_EXCL) {
  763.         UBYTE *p, c;
  764.         char *istr;                       /* fix to allow !cmd1;!cmd2 */
  765.         for(p = str; *p && *p != HOT_SEMI ; ++p);
  766.         c = *p;
  767.         *p = 0;
  768.         if( str[1]==HOT_EXCL ) str[1]='!';
  769.         istr = get_history((char *)str);
  770.         *p = c;
  771.         replace_head(istr);
  772.         str = format_insert_string( frameptr, str, istr );
  773.     }
  774.  
  775.     /*******************************************************
  776.      * Part one of the parser:
  777.      * The argument line is generated as an array of strings
  778.      */
  779.  
  780.     nextstr = str;
  781.     ac = 0;
  782.     do {              /* outer loop: each pass typically generates one av[ac] */
  783.         UBYTE *ptr, *arg;
  784.         signed char redir, doexpand, cont, inc;
  785.  
  786.         av[ac] = NULL;
  787.         cont = 1;
  788.         doexpand = redir = inc = 0;
  789.  
  790.         while (cont && elast) {       /* inner loop: adds one piece to av[ac] */
  791.             ptr = exarg(&nextstr,&elast);
  792.             inc = 1;
  793.             cont = (elast == 0x80);
  794.             if( (UBYTE)*ptr<0x80 )
  795.                 arg=ptr;
  796.             else {
  797.                 switch ((UBYTE)*ptr) {           /* arg must be set in every case */
  798.                 case HOT_IN:
  799.                     redir = -2;
  800.                 case HOT_OUT:
  801.                     if (cstat & (ST_NORED | ST_COND)) {         /* don't extract   */
  802.                         redir = 0;                          /* <> stuff if its */
  803.                         arg = ptr;                          /* external cmd.   */
  804.                         break;
  805.                     }
  806.                     ++redir;
  807.                     arg = ptr + 1;
  808.                     if (*arg == HOT_OUT && *ptr == HOT_OUT) {
  809.                         redir = 2;        /* append >> */
  810.                         ++arg;
  811.                     }
  812.                     else if (*arg == HOT_OUT && *ptr == HOT_IN) {
  813.                         /* AMK: fprintf(stderr,"caution: csh does not support \"<>\" redirection!\n"); */
  814.                         /* AMK: how about "redir = -4;" ? */
  815.                         redir = -4;
  816.                         ++arg;
  817.                     }
  818.                     cont = 1;
  819.                     break;
  820.                 case HOT_DOLLAR:
  821.                     /* restore args if from set command or pend_alias */
  822.                     if ((arg = get_var(LEVEL_SET, ptr + 1))) {
  823.                         UBYTE *pe, sv;
  824.                         while (pe = Index(arg,0xA0)) {
  825.                             sv = *pe;
  826.                             *pe = '\0';
  827.                             CHECKAV( 1 );
  828.  
  829.                             if (av[ac]) {
  830.                                 av[ac] = frealloc( frameptr,av[ac],Strlen(arg));
  831.                                 Strcat(av[ac++], arg);
  832.                             } else
  833.                                 av[ac++] = push_cpy(frameptr,arg);
  834.  
  835.                             *pe = sv;
  836.                             av[ac] = NULL;
  837.                             arg = pe+1;
  838.                         }
  839.                     } else
  840.                         arg = ptr;
  841.                     break;
  842.                 case HOT_LASTCD:
  843.                     if ((!ptr[1] || ptr[1]=='/')&&(arg=get_var(LEVEL_SET, v_lcd))) {
  844.                         if( ptr[1] ) {
  845.                             Strcpy(Buf,arg);
  846.                             Strcat(Buf,ptr+1);
  847.                             arg=(UBYTE*)Buf;
  848.                         }
  849. #if 0
  850.                         /* AMK: detecting DOS patterns BEGIN */
  851.                         /*else if (ptr[2]==HOT_PM1 || ptr[2]==HOT_PM2)*/
  852.                         else if (elast==0x80)
  853.                             arg = ptr;
  854.                         /* AMK: detecting DOS patterns END */
  855. #endif
  856.                     } else
  857.                         arg = ptr;
  858.                     break;
  859.                 case HOT_CURDIR:
  860.                     arg=ptr;
  861.                     if( !ptr[1] && elast!=0x80 || ptr[1]=='/' ) {
  862.                         if( ac==0 ) nobuiltin=1;
  863.                         arg= ptr[1]=='/' ? ptr+2 : ptr+1;
  864.                     }
  865.                     break;
  866.                 case HOT_PARDIR:
  867.                     arg=ptr;
  868.                     if( !ptr[2] && elast!=0x80 || ptr[2]=='/' )
  869.                         arg= ptr[2]=='/' ? ptr+2 : (UBYTE*)"/";
  870.                     break;
  871.  
  872. #if 1
  873.                 /* AMK --> detect DOS patterns */
  874.                 case HOT_PM1:
  875.                 case HOT_ECKL:
  876.                 case HOT_ECKR:
  877.                 /* <-- AMK */
  878. #endif
  879.                 case HOT_STAR:
  880.                 case HOT_QUES:
  881.                     if( !(cstat & ST_NOEXP) && !(pend_alias && *pend_alias=='*'))
  882.                         if( ac!=1 || av[1]&&*av[1] || *ptr!=HOT_QUES || ptr[1] )
  883.                             doexpand = 1;
  884.                     arg = ptr;
  885.                     break;
  886.                 default:
  887.                     arg = ptr;
  888.                     break;
  889.                 }
  890.             }
  891.  
  892.             /* Append arg to av[ac] */
  893.  
  894.             if (av[ac]) {
  895.                 av[ac] = frealloc( frameptr,av[ac],Strlen(arg));
  896.                 Strcat(av[ac], arg);
  897.             } else {
  898.                 av[ac] = push_cpy( frameptr, arg );
  899.             }
  900.  
  901.             if (elast != 0x80)
  902.                 break;
  903.         }
  904.  
  905.         /* one argument is now complete */
  906.  
  907.         backg   = *av[ac] && (UBYTE)av[ac][Strlen(av[ac])-1]==HOT_BACKG;
  908.         override= (UBYTE)*av[ac] == HOT_BSLASH;
  909.  
  910.         if( firstrun && (UBYTE)*av[0] == HOT_CURLL ) {
  911.             char *end;
  912.             av[0]++;
  913.             if( end=index(av[0],HOT_CURLR)) *end=0;
  914.             block=1;
  915.         }
  916.  
  917.         if( (UBYTE)*av[ac]==HOT_BEGOUT || (UBYTE)*av[ac]==HOT_APOSTR ) {
  918.             BPTR cout, oldcout= Myprocess->pr_COS;
  919.             FILE *in;
  920.             UBYTE *t;
  921.             int  apo;
  922.  
  923.             apo= (UBYTE)*av[ac]==HOT_APOSTR;
  924.             inc=0;
  925.             if( t=Index(av[ac]+1, apo ? HOT_APOSTR : HOT_ENDOUT ))
  926.                 *t=0;
  927.  
  928.             if(!(cout = Open(tempname(2),MODE_NEWFILE))) {
  929.                 err= 20;
  930.                 ierror (NULL, 504);
  931.             } else {
  932.                 Myprocess->pr_COS = DEVTAB(stdout) = cout;
  933.                 execute(av[ac]+2-apo);
  934.                 fflush(stdout);
  935.                 Close(cout);
  936.  
  937.                 if(!(in=fopen(tempname(2),"r"))) {
  938.                     err= 1;
  939.                     ierror (NULL, 504);
  940.                 } else {
  941.                     while( myfgets(Buf,in)) {
  942.                         char *str=Buf, *get, quote=0;
  943.                         CHECKAV( 1 );
  944.                         if( apo ) {
  945.                             while( *str==' ' ) str++;
  946.                             for( get=str; *get; ) {
  947.                                 /*
  948.                                    AMK:
  949.                                    Use 'o_cquote' here?
  950.                                 */
  951.                                 if( *get=='\"' )
  952.                                     quote=1-quote, get++;
  953.                                 else if( *get==' ' && !quote ) {
  954.                                     *get++=0;
  955.                                     CHECKAV( 1 );
  956.                                     while( *get==' ' ) get++;
  957.                                     if( !*get ) break;
  958.                                     av[ac++]=push_cpy(frameptr,str);
  959.                                     str=get;
  960.                                 } else
  961.                                     get++;
  962.                             }
  963.                             av[ac++]= push_cpy(frameptr,str);
  964.                         } else
  965.                             av[ac++]= push_cpy(frameptr,(UBYTE*)Buf);
  966.                     }
  967.                     fclose(in);
  968.                     DeleteFile(tempname(2));
  969.                     av[ac]=NULL;
  970.                 }
  971.             }
  972.  
  973.             Myprocess->pr_COS = DEVTAB(stdout) = oldcout;
  974.         }
  975.  
  976.         backtrans( (UBYTE *)av[ac] );
  977.  
  978.         if (doexpand) {                                  /* process expansion */
  979.             char **eav, **ebase;
  980.             int eac;
  981.             has_wild = 1;
  982.             eav = ebase = expand(av[ac], &eac);
  983.             inc = 0;
  984.  
  985.             /* AMK: test for pattern matching detection */
  986.             ++patterns_num;
  987.  
  988.             if (eav) {
  989.                 /* FUTURE: check retval */
  990.                 CHECKAV( eac );
  991.                 for (; eac; --eac, ++eav)
  992.                     av[ac++] = push_cpy(frameptr,*eav);
  993.                 free_expand (ebase);
  994.             }
  995.             else {
  996.                 /* AMK: test for pattern matching detection */
  997.                 ++patterns_fail;
  998. #if 0
  999.                 /* always warn if pattern doesn't match */
  1000. #endif
  1001. #if 0
  1002.                 if (o_nomatch) {
  1003.                     /* only warn, if _nomatch is set */
  1004.                     fprintf(stderr,"%s: No match.\n",av[0]);
  1005.                     /*
  1006.                        AMK: Abort command execution if pattern
  1007.                             does not match.  Don't abort if
  1008.                             "_nomatch" is unset.
  1009.                     */
  1010.                     /* AMK: how to abort here? */
  1011.                     goto done1;
  1012.                     /* AMK: or should we use done0? */
  1013.                     /* AMK: pipes are causing problems, when
  1014.                             jumping to done0 -- the program
  1015.                             after the pipe gets no stdin and
  1016.                             hangs (e.g. "echo *.dfsdf | wc")
  1017.                             With done1 the complete line is
  1018.                             aborted (further commands are ignored).
  1019.                             It works -- but differs from Unix-csh
  1020.                             behaviour!
  1021.                     */
  1022.                 }
  1023. #endif
  1024.             }
  1025.         } else if( av[ac] && av[ac][0]==')' ) {
  1026.             int i;
  1027.             UBYTE *pe, sv;
  1028.             for( i=ac-1; i>0; i-- )
  1029.                 if( *av[i]=='@' )
  1030.                     break;
  1031.             if( i>0 && av[i][Strlen(av[i])-1]=='(' ) {
  1032.                 extern int exec_fn_err;
  1033.                 char *avi=av[i], *last=av[ac];
  1034.                 av[i]=v_value; av[ac]=NULL;
  1035.                 arg=(UBYTE*)exec_function( avi+1, av+i, ac-i );
  1036.                 av[i]=avi;     av[ac]=last;
  1037.                 inc=0;
  1038.                 if( exec_fn_err<0 )
  1039.                     ac++;
  1040.                 else if( exec_fn_err>0 || !arg )
  1041.                     ac=i, av[ac]=NULL;
  1042.                 else {
  1043.                     ac=i;
  1044.                     while (pe = Index(arg,0xA0)) {
  1045.                         sv = *pe;
  1046.                         *pe = '\0';
  1047.                         CHECKAV( 1 );
  1048.                         av[ac++] = push_cpy(frameptr,arg);
  1049.                         *pe = sv;
  1050.                         arg= pe+1;
  1051.                     }
  1052.                     av[ac] = falloc(frameptr,Strlen(arg)+Strlen(last+1)+4);
  1053.                     Strcpy(av[ac],arg);
  1054.                     Strcat(av[ac++], last+1 );
  1055.                 }
  1056.             }
  1057.         }
  1058.  
  1059.         /*******************************
  1060.          * special handling of first arg
  1061.          */
  1062.  
  1063.         if( firstrun ) {                     /* we just found out the command */
  1064.             firstrun=0;
  1065.             command=av[0];
  1066.  
  1067.             if (command==NULL || *command==0)
  1068.                 goto done0;
  1069.  
  1070.             if( block )
  1071.                 pend_alias=command;
  1072.             else if ( override )
  1073.                 memmove( command, command+1, Strlen(command));
  1074.             else {
  1075.                 pend_alias=get_var(LEVEL_ALIAS,command);  /* if not \command */
  1076.                 if( pend_alias && pend_alias==from )
  1077.                     pend_alias=NULL;
  1078.             }
  1079.  
  1080.             if( pend_alias )
  1081.                 ccno= *pend_alias=='%' || *pend_alias=='*' ? 2 : 1;
  1082.             else
  1083.                 ccno= nobuiltin ? 0 : find_command(command);
  1084.             cstat=Command[ccno].stat;
  1085.  
  1086.             if ( !(cstat & ST_COND) && (disable || forward_goto) ) {
  1087.                 while (elast && elast != HOT_SEMI && elast != HOT_PIPE)
  1088.                     exarg(&nextstr,&elast);
  1089.                 goto done0;
  1090.             }
  1091.         }
  1092.  
  1093.         /********************************
  1094.          * handling of redirection
  1095.          */
  1096.  
  1097.         if( pendredir )
  1098.             redir=pendredir, pendredir=0;
  1099.  
  1100.         if (redir && !err) {                            /* store redirection  */
  1101.             char *file = (doexpand) ? av[--ac] : av[ac];
  1102.  
  1103.             if( !*file ) {
  1104.                 pendredir=redir;
  1105.             }
  1106.             else if (redir < 0) {
  1107.                 cin_name = file;
  1108.                 if (redir == -4) {    /* new OS2.0 <> redirection */
  1109.                     cout_name = cin_name;
  1110.                 }
  1111.             }
  1112.             else {
  1113.                 cout_name = file;
  1114.                 cout_append = (redir == 2);
  1115.             }
  1116.             inc = 0;
  1117.         }
  1118.  
  1119.         if (inc) {                                   /* check elast for space */
  1120.             ++ac;
  1121.             CHECKAV( 1 );                            /* FUTURE: check retval */
  1122.         }
  1123.     } while( elast==HOT_BLANK );
  1124.     av[ac] = NULL;
  1125.  
  1126.     /******************************************************************
  1127.      * Part two:
  1128.      * The argument line is processed (pipes, commands, recursive calls
  1129.      */
  1130.  
  1131.     /* process pipes via files */
  1132.  
  1133.     if (elast == HOT_PIPE && !err) {
  1134.         static int which;             /* 0 or 1 in case of multiple pipes */
  1135.         which = 1 - which;
  1136.         cout_name = tempname( which );
  1137.         cout_ispipe = 1;
  1138.     }
  1139.  
  1140.     if (err)
  1141.         goto done0;
  1142.  
  1143.     /* AMK: test for pattern matching detection */
  1144.     if (!o_nomatch && patterns_num==patterns_fail && patterns_num>0) {
  1145.         if (av[0])
  1146.             fprintf(stderr,"%s: No match.\n",av[0]);
  1147.         else
  1148.             fprintf(stderr,"No match.\n");
  1149.         goto done1;
  1150.     }
  1151.  
  1152.     {
  1153.         char *avline=NULL;
  1154.         char delim = ' ';
  1155.         BPTR  oldcin  = Myprocess->pr_CIS, cin=NULL;
  1156.         BPTR  oldcout = Myprocess->pr_COS, cout=NULL;
  1157.         char *cin_buf=NULL;
  1158.         struct FileHandle *ci=NULL;
  1159.         long oldbuf=NULL;
  1160.  
  1161.         if( backg ) {
  1162.             char *larg=av[ac-1];
  1163.             memmove( av+1, av, ac*sizeof(*av));
  1164.             command=av[0]=push_cpy( frameptr, (UBYTE*)o_rback);
  1165.             ccno=find_command(command);
  1166.             cstat=Command[ccno].stat;
  1167.             if( Strlen(larg)>1 )
  1168.                 larg[Strlen(larg)-1]=0, ac++;
  1169.         }
  1170.  
  1171.         if( ccno==2 || (cstat & ST_A0))            /* alias with argument */
  1172.             delim = 0xA0;
  1173.  
  1174.         if( cstat&ST_AVLINE || pend_alias || Verbose&VERBOSE_ALIAS )
  1175.             avline=compile_avf(frameptr,av,(pend_alias?1:0), ac, delim,ccno==1);
  1176.  
  1177. #if 0
  1178.         fprintf(stderr,"av[012]: %s %s %s, avline: %s\n",av[0]?av[0]:"╫",av[1]?av[1]:"╫",av[2]?av[2]:"╫",avline?avline:"(NULL)");
  1179.         {
  1180.         char *p = find_internal(av[0]);
  1181.         int cmdnum = find_command(av[0]);
  1182.         printf("find_command(av[0]) : %d (%s)\n",cmdnum,p?p:"(NULL)");
  1183.         if (Command[cmdnum].func == do_truerun)
  1184.             printf("Achtung, do_truerun() wird ausgefⁿhrt!\n");
  1185. /*
  1186.         if (stricmp(av[0],"run") == 0)
  1187.             printf("Achtung, C:RUN wird ausgefⁿhrt!\n");
  1188. */
  1189.         }
  1190. #endif
  1191.         if (Command[find_command(av[0])].func == do_truerun) {
  1192.             /*printf("Achtung, do_truerun() wird ausgefⁿhrt!\n");*/
  1193.             noclose_redir = TRUE;
  1194.         }
  1195.  
  1196.         fflush(stdout);
  1197.         LastCommand=command;
  1198.         if ( !(cstat & (ST_NORED | ST_COND))) { /* redirection not disabled */
  1199.             if (cin_name == cout_name) { /* redir == -4, which means <> redirection */
  1200.                 if (cin_name) {
  1201.                     filemap(cin_name,0);
  1202.  
  1203.                     cin = cout = NULL;
  1204.  
  1205.                     if (cin=Open(cin_name,MODE_OLDFILE)) {
  1206.                         if (stricmp(cin_name,"NIL:")==0) {
  1207.                             cout = Open(cin_name,MODE_OLDFILE);
  1208.                         }
  1209.                         else if (((struct FileHandle *)BADDR(cin))->fh_Port!=DOSFALSE) {
  1210.                             struct MsgPort *old;
  1211.                             old = SetConsoleTask(((struct FileHandle *)BADDR(cin))->fh_Type);
  1212.                             cout = Open("CONSOLE:",MODE_OLDFILE);
  1213.                             (void)SetConsoleTask(old);
  1214.                         }
  1215.                     }
  1216.                     if (!cin || !cout) {
  1217.                         fprintf(stderr,"%s: neither interactive nor NIL:\n",cin_name);
  1218.                         if (cin)  { Close(cin);  cin  = NULL; }
  1219.                         if (cout) { Close(cout); cout = NULL; }
  1220.                         cin_name = NULL;
  1221.                         cout_name = NULL;
  1222.                         ierror (NULL, 504);
  1223.                         err = 20;
  1224.                     } else {
  1225.                         redir_in=cin;
  1226.                         redir_out=cout;
  1227.  
  1228.                         if( !(cstat&ST_NORED)) {
  1229.                             if( !noclose_redir ) {
  1230.                                 Myprocess->pr_CIS = DEVTAB(stdin) = cin;
  1231.                                 Myprocess->pr_COS = DEVTAB(stdout) = cout;
  1232.  
  1233.                                 ci = (struct FileHandle *)(cin<<2);
  1234.                                 cin_buf = SAllocMem(202L, MEMF_PUBLIC);
  1235.                                 oldbuf = ci->fh_Buf;
  1236.                                 if (ci->fh_Buf == 0) /* fexec expects a CIS buffer */
  1237.                                     ci->fh_Buf = (long)cin_buf>>2;
  1238.                             }
  1239.                         }
  1240.                     }
  1241.                 }
  1242.             }
  1243.             else {
  1244.                 if (cin_name) {
  1245.                     filemap(cin_name,0);
  1246.                     if (!(cin = extOpen(cin_name,MODE_OLDFILE))) {
  1247.                         ierror (NULL, 504);
  1248.                         err = 20;
  1249.                         cin_name = NULL;
  1250.                     } else {
  1251.                         redir_in=cin;
  1252.                         if( !(cstat&ST_NORED)) {
  1253.                             if( !noclose_redir ) {
  1254.                                 Myprocess->pr_CIS = DEVTAB(stdin) = cin;
  1255.                                 ci = (struct FileHandle *)(cin<<2);
  1256.                                 cin_buf = SAllocMem(202L, MEMF_PUBLIC);
  1257.                                 oldbuf = ci->fh_Buf;
  1258.                                 if (ci->fh_Buf == 0) /* fexec expects a CIS buffer */
  1259.                                     ci->fh_Buf = (long)cin_buf>>2;
  1260.                             }
  1261.                         }
  1262.                     }
  1263.                 }
  1264.                 if (cout_name) {
  1265.                     filemap(cout_name,0);
  1266.                     if (cout_append && (cout=extOpen(cout_name,MODE_OLDFILE))) {
  1267.                         Seek(cout, 0L, OFFSET_END );
  1268.                     } else {
  1269. #if 1
  1270.                         /*
  1271.                          *  allow other programs to read contents of
  1272.                          *  redirected output, so we try MODE_READWRITE
  1273.                          */
  1274.  
  1275.                         /* first, clear file with MODE_NEWFILE */
  1276.                         BPTR pre_cout;
  1277.                         if (pre_cout = Open(cout_name,MODE_NEWFILE))
  1278.                             Close(pre_cout);
  1279.  
  1280.                         /* try MODE_READWRITE */
  1281.  
  1282.                         if (cout = extOpen(cout_name,MODE_READWRITE)) {
  1283.                             /*
  1284.                              *  Just to be sure, clear it again.
  1285.                              *  It's possible that MODE_NEWFILE failed
  1286.                              *  but MODE_READWRITE succeeded. In this
  1287.                              *  case the file still needs to be cleared.
  1288.                              */
  1289.                             SetFileSize (cout, 0L, OFFSET_BEGINNING);
  1290.                         }
  1291.                         else {
  1292.                             /*
  1293.                              *  MODE_READWRITE is not understood by all
  1294.                              *  handlers, eg NULL:, so additionally we
  1295.                              *  try it the old way with MODE_NEWFILE.
  1296.                              */
  1297.                             cout = extOpen(cout_name,MODE_NEWFILE);
  1298.                         }
  1299. #else
  1300.                         /*
  1301.                          *  allow other programs to read contents of
  1302.                          *  redirected output, so we use MODE_READWRITE
  1303.                          *  and SetFileSize(0) instead of just MODE_NEWFILE
  1304.                          */
  1305.                         if (cout = extOpen(cout_name,MODE_READWRITE)) {
  1306.                             if (SetFileSize (cout, 0L, OFFSET_BEGINNING) == -1L) {
  1307.                                 extClose(cout);
  1308.                                 cout = NULL;
  1309.                                 /*
  1310.                                 err = 20;
  1311.                                 ierror (NULL, 504);
  1312.                                 */
  1313.                             }
  1314.                         }
  1315.                         else {
  1316.                             /*
  1317.                              *  MODE_READWRITE is not understood by all
  1318.                              *  handlers, eg NULL:, so additionally we
  1319.                              *  try it the old way with MODE_NEWFILE.
  1320.                              */
  1321.                             cout = extOpen(cout_name,MODE_NEWFILE);
  1322.                         }
  1323. #endif
  1324.                     }
  1325.                     if (cout == NULL) {
  1326.                         err = 20;
  1327.                         ierror (NULL, 504);
  1328.                         cout_name = NULL;
  1329.                         cout_append = 0;
  1330.                     } else {
  1331.                         redir_out=cout;
  1332.                         if( !(cstat&ST_STORED))
  1333.                             if( !noclose_redir )
  1334.                                 Myprocess->pr_COS = DEVTAB(stdout) = cout;
  1335.                     }
  1336.                 }
  1337.             }
  1338.         }
  1339.  
  1340.         if( Verbose&VERBOSE_ALIAS ) {
  1341.             if( Verbose&VERBOSE_HILITE )
  1342.                 fprintf(stderr,"%s",o_hilite), fflush(stderr);
  1343.             if( pend_alias )
  1344.                 fprintf(stderr,"%-*s%s %s\n",alias_count,">",av[0],avline);
  1345.             else
  1346.                 fprintf(stderr,"%-*s%s\n",alias_count,">",avline);
  1347.             if( Verbose&VERBOSE_HILITE )
  1348.                 fprintf(stderr,"%s",o_lolite), fflush(stderr);
  1349.         }
  1350.  
  1351.         if( pend_alias && !backg ) {    /* don't expand alias if running in background */
  1352.             UBYTE *ptr, *scr;
  1353.             FRAME *subframe=NULL;
  1354.  
  1355.             if( ccno==2 ) {                         /* has arguments */
  1356.                 char *val=avline;
  1357.                 int clen;
  1358.  
  1359.                 ptr=pend_alias;
  1360.                 clen=Strlen(ptr)*2+20;
  1361.                 newframe( &subframe, clen+DEFAULTFRAME );
  1362.                 push_locals( (ROOT *)falloc( &subframe, sizeof(ROOT) ));
  1363.                 do {                                       /* set all args    */
  1364.                     char *varname, *gap=NULL;
  1365.                     for( varname= ++ptr; *ptr && *ptr!=' ' && *ptr!='%'; ++ptr);
  1366.                     if( *ptr=='%' && (gap=index(val,0xA0 )) ) *gap=0;
  1367.                     set_var( LEVEL_LOCAL, varname, val );
  1368.                     val= gap ? gap+1 : "";
  1369.                 } while( *ptr=='%' );
  1370.                 scr = falloc(&subframe,clen);
  1371.             } else {
  1372.                 int  clen=Strlen(pend_alias)+Strlen(avline)+20;
  1373.  
  1374.                 newframe( &subframe,3*clen+DEFAULTFRAME );
  1375.                 push_locals( (ROOT *)falloc( &subframe, sizeof(ROOT) ));
  1376.                 ptr = falloc( &subframe,clen );
  1377.                 sprintf(ptr,"%s %s",pend_alias,avline);
  1378.                 scr = falloc( &subframe, 2*clen );
  1379.             }
  1380.             preformat( ptr,scr );
  1381.             err=fcomm (scr,&subframe,pend_alias );
  1382.             pop_locals();
  1383.             deleteframe(subframe);
  1384.         } else {
  1385.             if (ac < Command[ccno].minargs + 1) {
  1386.                 show_usage( NULL );
  1387.                 err = 20;
  1388.             } else if (!err) {
  1389.                 int (*func)(char*,int)=Command[ccno].func;
  1390.                 get_opt( av, &ac, ccno, &err );
  1391.                 if( err || ccno>0 && ac==2 && !strcmp(av[1],"?") )
  1392.                     show_usage(av[0]);
  1393.                 else
  1394.                     err = (*func)(avline, Command[ccno].val); /*  do the call */
  1395.             }
  1396.         }
  1397.  
  1398.         if (err < 0)
  1399.             err = 20;
  1400.         if (E_stack == 0 )
  1401.             seterr(err);
  1402.         fflush(stderr);
  1403.  
  1404.         if (!(cstat & (ST_NORED | ST_COND))) {
  1405.             if (cin_name && !(cstat & ST_STORED)) {
  1406.  
  1407.                 if( !noclose_redir ) {
  1408.                     ci->fh_Buf = oldbuf;
  1409.                 }
  1410.  
  1411.                 fflush(stdin);
  1412.                 clearerr(stdin);
  1413.                 RESETIO( stdin );
  1414.  
  1415.                 if( !noclose_redir ) {
  1416.                     extClose(cin);
  1417.                     FreeMem(cin_buf, 202L);
  1418.                 }
  1419.             }
  1420.             if (cout_name && !(cstat & ST_STORED)) {
  1421.                 fflush(stdout);
  1422.                 clearerr(stdout);
  1423. #ifdef AZTEC_C
  1424.                 stdout->_flags &= ~_IODIRTY;    /* because of nil: device */
  1425. #endif
  1426.                 if( !noclose_redir ) {
  1427.                     extClose(cout);
  1428.                 }
  1429.  
  1430.                 cout_append = 0;
  1431.             }
  1432.         }
  1433.         Myprocess->pr_CIS = DEVTAB(stdin)  = oldcin;
  1434.         Myprocess->pr_COS = DEVTAB(stdout) = oldcout;
  1435.  
  1436.         if (cin_ispipe && cin_name)
  1437.             DeleteFile(cin_name);
  1438.         if (cout_ispipe) {
  1439.             cin_name = cout_name;         /* ok to assign.. static name */
  1440.             cin_ispipe = 1;
  1441.         } else {
  1442.             cin_name = NULL;
  1443.         }
  1444.         cout_name = NULL;
  1445.         cout_ispipe = 0;
  1446.     }
  1447.  
  1448. done0:
  1449.     {
  1450.         char *exc;
  1451.         if (err && E_stack==0) {
  1452.             exc = get_var(LEVEL_SET, v_except);
  1453.             if (err >= ((exc)?atoi(exc):1)) {
  1454.                 if (exc) {
  1455.                     ++H_stack, ++E_stack;
  1456.                     a0tospace(exc);
  1457.                     exec_command(exc);
  1458.                     --E_stack, --H_stack;
  1459.                 } else {
  1460.                     Exec_abortline = 1;
  1461.                 }
  1462.             }
  1463.             seterr(err);
  1464.         }
  1465.         if (elast != 0 && Exec_abortline == 0) {
  1466.             memmove( str, nextstr, Strlen(nextstr)+1 );
  1467.             goto nextcommand;
  1468.         }
  1469.         Exec_abortline = 0;
  1470.         if (cin_name)
  1471.             DeleteFile(cin_name);
  1472.     }
  1473. done1:
  1474.  
  1475.     av=oldav; ac=oldac; max_ac=oldmax;
  1476.     --alias_count;
  1477.  
  1478.     return err;                      /* TRUE = error occured    */
  1479. }
  1480.  
  1481.  
  1482. static UBYTE *
  1483. exarg(UBYTE **ptr, UBYTE *elast)
  1484. {
  1485.     UBYTE *end, *start;
  1486.  
  1487.     start = end = *ptr;
  1488.     while ( *(signed char *)end>0 || *end && *end != 0x80 &&
  1489.              *end != HOT_SEMI &&  *end != HOT_PIPE && *end != HOT_BLANK)
  1490.         ++end;
  1491.     *elast = *end;
  1492.     *end = '\0';
  1493.     *ptr = end + 1;
  1494.     return start;
  1495. }
  1496.  
  1497.  
  1498. static void
  1499. newframe(FRAME **frameptr, int bytes)
  1500. {
  1501.     FRAME *new;
  1502.  
  1503.     new=salloc( bytes + 4 + sizeof(FRAME) );
  1504.     new->next= *frameptr;
  1505.     new->bytesleft = bytes;
  1506.     new->ptr       = new->mem;
  1507.     *frameptr=new;
  1508. }
  1509.  
  1510. static void *
  1511. falloc( FRAME **frameptr, int bytes )
  1512. {
  1513.     FRAME *frame= *frameptr;
  1514.     char *mem;
  1515.  
  1516.     bytes+=2;                                    /* 2 extra bytes for do_run  */
  1517.     bytes|=3;
  1518.     bytes++; 
  1519.  
  1520.     if( frame->bytesleft <= bytes )
  1521.         newframe( frameptr, bytes+DEFAULTFRAME ), frame = *frameptr;
  1522.  
  1523.     mem=frame->ptr;
  1524.     frame->bytesleft-=bytes;
  1525.     frame->ptr      +=bytes;
  1526.     return mem;
  1527. }
  1528.  
  1529. static void *
  1530. frealloc( FRAME **frameptr, char *oldstring, int morebytes )
  1531. {
  1532.     char *mem=oldstring;
  1533.  
  1534.     morebytes|=3;
  1535.     morebytes++; 
  1536.  
  1537.     if( (*frameptr)->bytesleft <= morebytes ) {
  1538.         int oldlen=(*frameptr)->ptr-oldstring;
  1539.         newframe( frameptr, oldlen+morebytes+DEFAULTFRAME );
  1540.         mem= (*frameptr)->ptr;
  1541.         strcpy((*frameptr)->ptr,oldstring);
  1542.         oldlen+=morebytes;
  1543.         (*frameptr)->ptr      +=oldlen;
  1544.         (*frameptr)->bytesleft-=oldlen;
  1545.     }
  1546.     (*frameptr)->bytesleft-=morebytes;
  1547.     (*frameptr)->ptr      +=morebytes;
  1548.     return mem;
  1549. }
  1550.  
  1551. static void
  1552. funalloc( FRAME **frameptr, int bytes )
  1553. {
  1554.     bytes&=~3;
  1555.     (*frameptr)->bytesleft+=bytes;
  1556.     (*frameptr)->ptr      -=bytes;
  1557. }
  1558.  
  1559.  
  1560.  
  1561. static void
  1562. deleteframe(FRAME *frame)
  1563. {
  1564.     FRAME *nxt;
  1565.  
  1566.     for( ; frame; frame=nxt ) {
  1567.         nxt=frame->next;
  1568.         free(frame);
  1569.     }
  1570. }
  1571.  
  1572. /*
  1573.  * Insert 'from' string in front of 'str' while deleting the
  1574.  * first entry in 'str'.  if freeok is set, then 'str' will be
  1575.  * free'd
  1576.  */
  1577.  
  1578. static UBYTE *
  1579. format_insert_string(FRAME **frameptr, UBYTE *str, char *from)
  1580. {
  1581.     UBYTE *new, *strskip;
  1582.     int len;
  1583.  
  1584.     strskip=skipword( str );
  1585.     len = Strlen(from)*3+20;
  1586.     new = falloc( frameptr, len);
  1587.     preformat(from, new);
  1588.     funalloc( frameptr, len -Strlen(new)  - 2 );
  1589.     frealloc( frameptr, (char*)new, Strlen(strskip)+2);
  1590.     strcat((char*)new, (char*)strskip);
  1591.     new[Strlen(new)+1] = 0;
  1592.     return new;
  1593. }
  1594.  
  1595. static UBYTE *
  1596. skipword( UBYTE *strskip )
  1597. {
  1598.     for ( ; *(signed char *)strskip>0
  1599.         || *strskip && *strskip != HOT_BLANK 
  1600.         && *strskip != HOT_SEMI && *strskip != HOT_PIPE
  1601.         && *strskip != 0x80; ++strskip);
  1602.     return strskip;
  1603. }
  1604.  
  1605. char *
  1606. find_internal( char *str )
  1607. {
  1608.     return Command[find_command(str)].name;
  1609. }
  1610.  
  1611. static int
  1612. find_command( char *str )
  1613. {
  1614.     int i, len = Strlen(str);
  1615.     struct COMMAND *com;
  1616.     char c = *str;
  1617.  
  1618.     if( TRUE /*o_abbrev!=2*/ )
  1619.         for( com=Command, i=0; com->func; com++, i++ )
  1620.             if ( c == *com->name && !strncmp(str, com->name, len))
  1621.                 if(o_abbrev&1 || len==Strlen(com->name))
  1622.                     return i;
  1623.     if( !stricmp(FilePart(str),"Execute") || !stricmp(FilePart(str),"Run"))
  1624.         return COM_EXEC;
  1625.  
  1626.     return 0;
  1627. }
  1628.  
  1629. /* for usage in other modules, i.e. in comm3.c/do_truerun() */
  1630. int find_command2( char *str )
  1631. {
  1632.     return(find_command(str));
  1633. }
  1634.  
  1635. int exec_fn_err;
  1636.  
  1637. extern struct FUNCTION {
  1638.     short id, minargs, maxargs;
  1639.     char *name;
  1640. } Function[];
  1641.  
  1642.  
  1643. char *gotfunc( int i, char **fav, int fac );
  1644.  
  1645. char *
  1646. exec_function( char *str, char **fav, int fac)
  1647. {
  1648.     int len=Strlen(str)-1, i;
  1649.  
  1650.     exec_fn_err=0;
  1651.     for (i = 0; Command[i].func; ++i)
  1652.         if ( Command[i].stat&ST_FUNC && !strncmp(str,Command[i].name,len)) {
  1653.             if( fac<Command[i].minargs ) {
  1654.                 exec_fn_err=20;
  1655.                 return NULL;
  1656.             } else {
  1657.                 int (*func)( void )=Command[i].func;
  1658.                 char **oldav=av;
  1659.                 int  oldac=ac;
  1660.                 av=fav-1, ac=fac+1;
  1661.                 exec_fn_err=(*func)();
  1662.                 av=oldav, ac=oldac;
  1663.                 return get_var( LEVEL_SET, fav[0] );
  1664.             }
  1665.         }
  1666.     for (i = 0; Function[i].id; ++i)
  1667.         if ( len==Strlen(Function[i].name)&&!strncmp(str,Function[i].name,len))
  1668.             return gotfunc( i,fav,fac );
  1669.  
  1670.     exec_fn_err = -1;
  1671.     return NULL;
  1672. }
  1673.  
  1674. int
  1675. echofunc(void)
  1676. {
  1677.     int  i;
  1678.     char *str;
  1679.  
  1680.     if( !strlen(av[0]) ) return -1;
  1681.     exec_fn_err=0;
  1682.     for (i = 0; Function[i].id; ++i)
  1683.         if ( !strcmp(av[0],Function[i].name)) {
  1684.             if(str=gotfunc( i,av,ac ))
  1685.                 printf("%s\n",str);
  1686.             return exec_fn_err;
  1687.         }
  1688.     return -1;
  1689. }
  1690.  
  1691.  
  1692. char *
  1693. gotfunc( int i, char **fav, int fac )
  1694. {
  1695.     fac--; fav++;
  1696.     if( fac<Function[i].minargs ) {
  1697.         fprintf( stderr, "Not enough arguments for @%s\n",
  1698.                           Function[i].name );
  1699.         exec_fn_err=20;
  1700.         return NULL;
  1701.     } else if( fac>Function[i].maxargs ) {
  1702.         if( ac > Function[i].maxargs )
  1703.             fprintf( stderr, "Too many arguments for @%s\n",
  1704.                               Function[i].name );
  1705.         exec_fn_err=20;
  1706.         return NULL;
  1707.     } else {
  1708.         exec_fn_err=dofunc( Function[i].id, fav, fac);
  1709.         return exec_fn_err ? (char *)NULL : (char *)get_var(LEVEL_SET, v_value);
  1710.     }
  1711.     return NULL;
  1712. }
  1713.  
  1714.  
  1715.  
  1716. do_help()
  1717. {
  1718.     struct COMMAND *com;
  1719.     int i=0;
  1720.  
  1721.     for (com = &Command[FIRSTCOMMAND]; com->func; ++com) {
  1722.         printf ("%-12s", com->name);
  1723.         if (++i % 6 == 0) printf("\n");
  1724.     }
  1725.  
  1726.     if (i % 6 != 0) printf("\n");
  1727.  
  1728.     if (options&1) {
  1729.         int num;
  1730.         printf("\n");
  1731.         for (i=0,num=0; Function[num].id; ++num) {
  1732.             printf("@%-11s",Function[num].name);
  1733.             if (++i % 6 == 0) printf("\n");
  1734.         }
  1735.         if (i % 6 != 0) printf("\n");
  1736.     }
  1737.  
  1738.     printf("\nUse   man <command>   for more information\n");
  1739.     return 0;
  1740. }
  1741.  
  1742. do_nothing()
  1743. {
  1744.     return 0;
  1745. }
  1746.  
  1747. static char *
  1748. push_cpy(FRAME **frameptr, void *s)
  1749. {
  1750.     return strcpy(falloc(frameptr,Strlen(s)+1), s);
  1751. }
  1752.  
  1753. void
  1754. exec_every(void)
  1755. {
  1756.     char *str = o_every;
  1757.  
  1758.     if (str) {
  1759.         ++H_stack, ++E_stack;
  1760.         a0tospace( str );
  1761.         exec_command(str);
  1762.         --E_stack, --H_stack;
  1763.     }
  1764. }
  1765.  
  1766. char *
  1767. a0tospace( char *str )
  1768. {
  1769.     char *get=str, *put=str;
  1770.  
  1771.     while( *get )
  1772.         if( (UBYTE)*get==0xA0 )
  1773.             *put++=' ', get++;
  1774.         else 
  1775.             put++,get++;
  1776.     return str;
  1777. }
  1778.  
  1779. void
  1780. show_usage( char *str )
  1781. {
  1782.     int ccno, first=0, err=0;
  1783.     char *get, *put, buf[300];
  1784.  
  1785.     if( !str )
  1786.         str=LastCommand, err=1;
  1787.     for( put=str; *put && (*put&127)!=32; put++ ) ;
  1788.     *put=0;
  1789.  
  1790.     put=buf;
  1791.     ccno = find_command (str);
  1792.     if( get= Command[ccno].usage ) {
  1793.         do {
  1794.             put+=sprintf(put, first++?"       %s ":"Usage: %s ",
  1795.                          Command[ccno].name );
  1796.             if( *get=='-' ) {
  1797.                 *put++='['; *put++='-';
  1798.                 get++;
  1799.                 while( *get && *get!=' ' && *get!=',' )
  1800.                     *put++ = *get++;
  1801.                 *put++=']';
  1802.             }
  1803.             while( *get && *get!=','  )
  1804.                 *put++ = *get++;
  1805.             *put++='\n';
  1806.         } while( *get++ );
  1807.         *put=0;
  1808.         fprintf( err ? stderr : stdout, "%s", buf );
  1809.     }
  1810. }
  1811.  
  1812. do_exec( char *str )
  1813. {
  1814.     if( !options )
  1815.         return execute( next_word( str ) );
  1816.     execute( next_word(next_word( str )));
  1817.     return 0;
  1818. }
  1819.  
  1820. static int
  1821. checkav( FRAME **frameptr, int n )
  1822. {
  1823.     char **tmp;
  1824.     int newac;
  1825.  
  1826.     if( ac+n+10>=max_ac ) {
  1827.         newac=max_ac+n+40;
  1828.         tmp=(char **)falloc(frameptr,newac*sizeof(char *));
  1829.         memcpy(tmp,av,max_ac*sizeof(char *));
  1830.         av=tmp; max_ac=newac;
  1831.     }
  1832.     return 0;
  1833. }
  1834.  
  1835. /*    Parse the options specified in sw[]
  1836.     Setting a bit in global variable options
  1837.     for each one found
  1838. */
  1839.  
  1840. int
  1841. get_opt( char **av, int *ac, int ccno, int *err )
  1842. {
  1843.     static char opts[2];
  1844.     char **get=av+1,**put=av+1, *c, *s, *str;
  1845.     int  i=1, l, usage=0, nac;
  1846.     long oldopts, origopts=options;
  1847.  
  1848.     *err=0;
  1849.     options=0;
  1850.     if( !ccno )
  1851.         return 0;
  1852.     if( ccno>0 ) {
  1853.         if ((str=Command[ccno].options)==NULL)
  1854.             return 0;   /* command has no options */
  1855.     }
  1856.     else
  1857.         str=opts, opts[0] = -ccno;
  1858.  
  1859.     for( ; i<*ac && *av[i]=='-'; i++, get++ ) {
  1860.         if( !*(c = *get+1))
  1861.             goto stop;
  1862.         if(  *c=='-' && !c[1] ) {
  1863.             i++, get++;
  1864.             goto stop;
  1865.         }
  1866.         oldopts=options;
  1867.         for ( ; *c ; c++) {
  1868.             if( (*c<'a' || *c>'z') && (*c<'A' || *c>'Z') )
  1869.                 { options=oldopts; goto stop; }
  1870.             for( l=0, s=str; *s && *s != *c; ++s )
  1871.                 ++l;
  1872.             if ( *s )
  1873.                 options |= (1 << l);
  1874.             else if( !usage ) {
  1875.                 usage=1;
  1876.                 if( ccno>0 )
  1877.                     *err=20;
  1878.             }
  1879.         }
  1880.     }
  1881. stop:
  1882.     if( ccno>0 ) {
  1883.         for( nac=1; i<*ac; i++ )
  1884.             *put++ = *get++, nac++;
  1885.         *put=NULL;
  1886.         *ac=nac;
  1887.     } else {
  1888.         i=options;
  1889.         options=origopts;
  1890.         return i;
  1891.     }
  1892.     return 0;
  1893. }
  1894.  
  1895. #if 0
  1896. USHORT Options[160];
  1897.  
  1898. int
  1899. do_options()
  1900. {
  1901.     for( i=1; i<ac; i+=2 ) {
  1902.         if( ac-i<=1 )
  1903.             { ierror( av[i], 500 ); return 20; }
  1904.         if( *av[i+1]!='-' )
  1905.             { ierror( av[i+1], 500 ); return 20; }
  1906.         options=0;
  1907.         parseopts( av[i+1]+1 );
  1908.     }
  1909. }
  1910. #endif
  1911.  
  1912. extern char *MyMem;
  1913. static char Pipe[3][32];
  1914.  
  1915. static char *
  1916. tempname( int which )
  1917. {
  1918.     sprintf(Pipe[which],"%spipe%c%d_%lx",o_pipe,'A'+which,alias_count,MyMem);
  1919.     return Pipe[which];
  1920. }
  1921.  
  1922. int
  1923. hasspace( char *s )
  1924. {
  1925.     if( !*s )
  1926.         return 1;
  1927.     for ( ; *s; s++)
  1928.         if (ISSPACE(*s) || *s==';') return 1;
  1929.     return 0;
  1930. }
  1931.  
  1932. static char *
  1933. compile_avf(FRAME **framep,char **av, int start, int end, char delim, int quote)
  1934. {
  1935.     char *cstr, *p, *s;
  1936.     int len, i;
  1937.  
  1938.     len = 3;
  1939.     for (i = start; i < end; ++i) len += Strlen(av[i]) + 3;
  1940.     if( framep ) {
  1941.         p = cstr = falloc(framep,len);
  1942.     } else 
  1943.         p = cstr = salloc(len);
  1944.     *cstr = '\0';
  1945.  
  1946.     for (i = start; i < end; ++i) {
  1947.         if (quote && hasspace(av[i]))
  1948.             p += sprintf(p, "\"%s\"", av[i]);
  1949.         else {
  1950.             for( s=av[i]; *p++ = *s++; ) ;
  1951.             p--;
  1952.         }
  1953.         if (i+1 < end) *p++=delim;
  1954.     }
  1955.     *p='\0';
  1956.  
  1957.     return cstr;
  1958. }
  1959.  
  1960. char *
  1961. compile_av(char **av, int start, int end, char delim, int quote)
  1962. {
  1963.     return compile_avf(NULL,av, start, end, delim, quote);
  1964. }
  1965.  
  1966. int
  1967. myfgets( char *buf, FILE *in )
  1968. {
  1969.     int l;
  1970.     char *ret;
  1971.     if( ret=fgets(buf,253,in) ) {
  1972.         l=Strlen(buf);
  1973.         if( buf[l-1]=='\n' )
  1974.             buf[l-1]=0;
  1975.     }
  1976.     return ret!=NULL && !dobreak();
  1977. }
  1978.  
  1979.  
  1980.  
  1981. /* AMK: last char of a string */
  1982. char lastch(char *str)
  1983. {
  1984.     int len;
  1985.     if (str) {
  1986.         if (len=strlen(str))
  1987.             return(str[len-1]);
  1988.         else
  1989.             return('\0');
  1990.     }
  1991.     else
  1992.         return('\0');
  1993. }
  1994.  
  1995.  
  1996.  
  1997. /* AMK: replaced ARP's BtoCStr() and CtoBStr() with own routines */
  1998.  
  1999. ULONG BtoCStr(char *cstr, BSTR bstr, LONG maxlen)
  2000. {
  2001.     char *astr;
  2002.     int i;
  2003.     astr = (char *)(bstr << 2);
  2004.  
  2005.     for ( i=1; i <= astr[0] && i <= maxlen; i++)
  2006.         cstr[i-1] = astr[i];
  2007.     cstr[i-1] = '\0';
  2008.     return((ULONG)(i-1));
  2009. }
  2010.  
  2011. ULONG CtoBStr(char *cstr, BSTR bstr, LONG maxlen)
  2012. {
  2013.     char *astr;
  2014.     int i,l;
  2015.     astr = (char *)(bstr << 2);
  2016.  
  2017.     for ( i=0,l=strlen(cstr); i < l && i < maxlen && i < 255; i++)
  2018.         astr[i+1] = cstr[i];
  2019.     astr[0] = i;
  2020.     return((ULONG)(i));
  2021. }
  2022.  
  2023.